<template>
	<div class="page-gateway">
		<form class="form" @submit="onset">
			<div class="state">
				<div class="state_txt">
					<text>网关机器码：</text>
					<input name="UUID" type="text" cursor-spacing="50px" :value="UUID" placeholder="扫描网关二维码获取" />
				</div>
				<div class="state_txt">TIPS：启动通电须打开蓝牙，写入配置时需按网关上按键（闪蓝灯）</div>
				<div class="state_txt">说明：默认访问密码为000000，建议定期更换访问密码，长按网关按键20秒重置密码。</div>
				<button class="bnt" form-type="submit">配置网关WIFI</button>
				<button class="bnt" @tap="onAppKey">修改网关密码</button>
			</div>
		</form>

		<div :class="['popdiv', { show: showWifi }]">
			<div class="popcont">
				<div class="pop_text">
					<div class="pop_title">请选择WIFI（不支持5G版本）</div>
					<div class="pop_list">
						<text v-for="item in wifiList" :key="item.BSSID" :class="wifiBSSID === item.BSSID ? 'crumb' : ''" @tap="selectWifi(item.BSSID)">
							{{ item.SSID }}
						</text>
					</div>
					<div class="pop_bnt flex row-between">
						<button @tap="closeWifi">取消</button>
						<button @tap="confirmWifi">设置</button>
					</div>
				</div>
			</div>
		</div>

		<div :class="['popdiv', { show: showPassword }]">
			<div class="popcont">
				<div class="pop_text flex row-between">
					<form @submit="formSubmit">
						<div class="pop_title">请输入WIFI密码</div>
						<div class="pop_input">
							<input name="password" cursor-spacing="20" value="" />
						</div>
						<div class="pop_bnt flex row-between">
							<button @tap="closePassword">取消</button>
							<button form-type="submit">确认</button>
						</div>
					</form>
				</div>
			</div>
		</div>

		<div :class="['popdiv', { show: showUpdate }]">
			<div class="popcont">
				<div class="pop_text">
					<form @submit="updateSubmit">
						<div class="pop_title">请输入原密码</div>
						<div class="pop_input">
							<input name="old_password" cursor-spacing="20" value="" />
						</div>
						<div class="pop_title">请输入新密码</div>
						<div class="pop_input">
							<input name="new_password" cursor-spacing="20" value="" />
						</div>
						<div class="pop_bnt flex row-between">
							<button @tap="closeUpdate">取消</button>
							<button form-type="submit">确认</button>
						</div>
					</form>
				</div>
			</div>
		</div>
	</div>
</template>

<script>
import utils from '@/utils';

export default {
	name: 'PageGateway',
	data() {
		return {
			hiddenAppKeyPut: true,
			UUID: '0030100U0xFAeGG01',
			wifiBSSID: '',
			wifiList: [],
			selectedWifi: null,
			showWifi: false,
			showPassword: false,
			showUpdate: false
		};
	},
	methods: {
		onAppKey() {
			this.hiddenAppKeyPut = true;
			this.showUpdate = true;
		},
		closeUpdate() {
			this.showUpdate = false;
		},
		onset() {
			uni.startWifi({
				success: () => uni.getWifiList({ complete: (_) => null })
			});
			uni.onGetWifiList((res) => {
				const wifiList = [];
				if (res.wifiList) {
					// 排除5G
					for (let i = 0; i < res.wifiList.length; i++) {
						if (res.wifiList[i].frequency && res.wifiList[i].frequency > 5000) {
							continue;
						}
						if (res.wifiList[i].SSID !== '') {
							wifiList.push(res.wifiList[i]);
						}
					}
				}
				this.wifiList = wifiList;
			});

			this.showWifi = true;
		},
		selectWifi(id) {
			this.wifiBSSID = id;
		},
		closeWifi() {
			this.showWifi = false;
		},
		confirmWifi() {
			if (!this.wifiBSSID) {
				uni.showToast({
					title: '请选择WIFI',
					icon: 'none'
				});
				return;
			}

			let selectedWifi = {};
			for (let i = 0; i < this.wifiList.length; i++) {
				if (this.wifiList[i].BSSID === this.wifiBSSID) {
					selectedWifi = this.wifiList[i];
				}
			}

			if (selectedWifi && selectedWifi.secure === true) {
				this.selectedWifi = selectedWifi;
				this.showWifi = false;
				this.showPassword = true;
			} else if (selectedWifi && selectedWifi.secure === false) {
				this.showWifi = false;
				// 没有密码，直接连接
				uni.connectWifi({
					SSID: selectedWifi.SSID,
					BSSID: selectedWifi.BSSID,
					password: '',
					success() {
						uni.showToast({
							title: '请稍等...',
							icon: 'none'
						});
						this.startMatch(selectedWifi, '').catch((_) => false);
					},
					fail() {
						uni.showToast({
							title: 'WIFI连接失败',
							icon: 'none'
						});
					}
				});
			} else {
				uni.showToast({
					title: 'WIFI选择有误',
					icon: 'none'
				});
			}
		},
		closePassword() {
			this.showWifi = false;
			this.showPassword = false;
		},
		formSubmit(e) {
			const password = e.detail.value.password;
			this.startMatch(this.selectedWifi, password).catch((_) => false);
		},
		updateSubmit(e) {
			const oldPassword = e.detail.value.old_password;
			const newPassword = e.detail.value.new_password;
			if (oldPassword.length !== 6) {
				uni.showModal({
					content: '旧密码长度需要为6位',
					showCancel: false,
					confirmText: '我知道了'
				});
				return;
			}
			if (newPassword.length !== 6) {
				uni.showModal({
					content: '新密码长度需要为6位',
					showCancel: false,
					confirmText: '我知道了'
				});
				return;
			}
			const data = {
				UUID: this.UUID,
				oldKey: oldPassword,
				newKey: newPassword
			};
			utils.postUpdateKey(
				data,
				/**
				 * @param {Object} res
				 * @property {string} updateKey
				 **/
				(res) => {
					if (res.updateKey && (res.updateKey === 'ok' || res.updateKey === 'success')) {
						uni.showModal({
							content: '密码修改成功',
							showCancel: false,
							confirmText: '我知道了'
						});
						this.hiddenAppKeyPut = false;
						this.showUpdate = false;
					} else if (res.updateKey) {
						uni.showModal({
							content: '修改失败：' + res.updateKey,
							showCancel: false,
							confirmText: '我知道了'
						});
					}
				}
			);
		},
		async startMatch(selectWifi, password) {
			const ssid = selectWifi.SSID;
			if (!ssid) {
				return;
			}
			// #ifdef MP-WEIXIN
			const res = await utils.checkBluetooth().catch((_) => false);
			if (!res) {
				return;
			}
			// #endif

			uni.showLoading({ title: '请按网关配网键' });

			const UUID = this.UUID;
			const toBJU = UUID.substring(6, 10);

			uni.openBluetoothAdapter({
				success: () => {
					let mydevice = null;
					const success = () => {
						let trycnt = 0;
						uni.onBluetoothDeviceFound((devices) => {
							uni.showLoading({ title: '设备搜索(' + trycnt + ')...' });
							for (let i = 0; i < devices.devices.length; i++) {
								const view = new Uint8Array(devices.devices[i].advertisData);
								if (view.length > 20) {
									const checkU = String.fromCharCode(view[15]) + String.fromCharCode(view[16]) + String.fromCharCode(view[17]) + String.fromCharCode(view[18]);
									if (toBJU === checkU) {
										mydevice = devices.devices[i];
										trycnt = 100;
										break;
									}
								}
							}
							if (trycnt >= 50) {
								if (uni.offBluetoothDeviceFound) {
									uni.offBluetoothDeviceFound((_) => null);
								}
								trycnt = 0;
								uni.stopBluetoothDevicesDiscovery({
									success: () => {
										if (!mydevice) {
											return;
										}
										const deviceId = mydevice.deviceId;
										const data = { UUID };
										utils.postGateway(data, (res) => {
											if (!res || !res.verify) {
												return;
											}
											const verifyArr = this.verifyBuffer('VERIFY' + res.verify);
											const ssidPadNum = 32 - this.strLength(ssid);
											const passwordPadNum = 64 - password.length;
											let writeStr = 'WRITE' + String.fromCharCode(0x96) + this.strUtf8(ssid); // String.fromCharCode(ssid);
											for (let i = 0; i < ssidPadNum; i++) {
												writeStr += String.fromCharCode(0xff);
											}
											writeStr += password;
											for (let i = 0; i < passwordPadNum; i++) {
												writeStr += String.fromCharCode(0xff);
											}
											writeStr += '00000000000000000000000000000000';

											const writeArr = this.writeBuffer(writeStr);
											const dataArr = verifyArr.concat(writeArr);

											if (dataArr.length === 8) {
												uni.createBLEConnection({
													// 连接目标设备
													deviceId: deviceId,
													timeout: 2000,
													success: () => {
														uni.showLoading({ title: '开始保存配置...' });
														uni.getBLEDeviceServices({
															deviceId: deviceId,
															success: () => {
																const serviceId = '00000001-0000-1000-8000-00805F9B34FB';
																const wcharacteristicId = '00000003-0000-1000-8000-00805F9B34FB';
																let successNum = 0;
																uni.getBLEDeviceCharacteristics({
																	deviceId: deviceId,
																	serviceId: serviceId,
																	success: () => {
																		uni.showLoading({ title: '保存配置...' });
																		for (let i = 0; i < dataArr.length; i++) {
																			const data = dataArr[i];
																			uni.writeBLECharacteristicValue({
																				deviceId: deviceId,
																				serviceId: serviceId,
																				characteristicId: wcharacteristicId,
																				value: data,
																				success: () => successNum++,
																				fail: () => {
																					uni.closeBLEConnection({
																						deviceId: mydevice.deviceId,
																						complete: () => {
																							uni.hideLoading();
																							uni.showToast({
																								title: '配置失败，请重试!'
																							});
																							uni.closeBluetoothAdapter({ complete: (_) => null });
																						}
																					});
																				},
																				complete: () => {
																					uni.showLoading({
																						title: '保存配置...'
																					});
																					if (successNum === dataArr.length) {
																						uni.closeBLEConnection({
																							deviceId: deviceId,
																							complete: () => {
																								uni.hideLoading();
																								uni.showModal({
																									content: '配置完成，等待重启',
																									showCancel: false,
																									confirmText: '我知道了'
																								});
																								this.closePassword();
																								uni.closeBluetoothAdapter({ complete: (_) => null });
																							}
																						});
																					}
																				}
																			});
																			this.sleep(200);
																		}
																	},
																	fail: () =>
																		uni.closeBluetoothAdapter({
																			complete: () => {
																				uni.hideLoading();
																				uni.showModal({
																					content: '配置失败，请重试!!',
																					showCancel: false,
																					confirmText: '我知道了'
																				});
																			}
																		})
																});
															},
															fail: () =>
																uni.closeBluetoothAdapter({
																	complete: () => {
																		uni.hideLoading();
																		uni.showModal({
																			content: '配置失败，请重试!!!',
																			showCancel: false,
																			confirmText: '我知道了'
																		});
																	}
																})
														});
													},
													fail: () =>
														uni.closeBluetoothAdapter({
															complete: () => {
																uni.hideLoading();
																uni.showModal({
																	content: '配置失败，请重试!!!!',
																	showCancel: false,
																	confirmText: '我知道了'
																});
															}
														})
												});
											}
										});
									}
								});
							}
							trycnt++;
						});
					};
					const options = {
						allowDuplicatesKey: true,
						interval: 100,
						powerLevel: 'high',
						success
					};
					uni.startBluetoothDevicesDiscovery(options);
				},
				fail() {
					uni.hideLoading();
					uni.showModal({
						content: '蓝牙打开失败，先打开蓝牙并设置隐私权限',
						showCancel: false,
						confirmText: '我知道了'
					});
				}
			});
		},
		writeBuffer(dataString) {
			let data;
			const arr = [];
			while (dataString.length > 20) {
				data = dataString.substring(0, 20);
				const buffer = new ArrayBuffer(20);
				const dataView = new DataView(buffer);
				for (let i = 0; i < 20; i++) {
					dataView.setUint8(i, data.charCodeAt(i));
				}
				arr.push(buffer);
				dataString = dataString.substring(20, dataString.length);
			}

			data = dataString;
			const buffer = new ArrayBuffer(data.length);
			const dataView = new DataView(buffer);

			for (let i = 0; i < data.length; i++) {
				dataView.setUint8(i, data.charCodeAt(i));
			}
			arr.push(buffer);
			return arr;
		},
		verifyBuffer(dataString) {
			if (dataString.length !== 22) return [];

			const arr = [];
			const buffer = new ArrayBuffer(14);
			const dataView = new DataView(buffer);
			for (let i = 0; i < 6; i++) {
				dataView.setUint8(i, dataString.charCodeAt(i));
			}
			dataString = dataString.substring(6, dataString.length);
			for (let i = 0; i < 8; i++) {
				dataView.setUint8(i + 6, parseInt(dataString.substring(i * 2, i * 2 + 2), 16));
			}

			arr.push(buffer);
			return arr;
		},
		strLength(str) {
			// eslint-disable-next-line no-control-regex
			return str.replace(/[^\x00-\xff]/g, '***').length;
		},
		strUtf8(str) {
			const back = [];
			let backStr = '';
			for (let i = 0; i < str.length; i++) {
				const code = str.charCodeAt(i);
				if (code >= 0x00 && code <= 0x7f) {
					back.push(code);
				} else if (code >= 0x80 && code <= 0x7ff) {
					back.push(192 | (31 & (code >> 6)));
					back.push(128 | (63 & code));
				} else if ((code >= 0x800 && code <= 0xd7ff) || (code >= 0xe000 && code <= 0xffff)) {
					back.push(224 | (15 & (code >> 12)));
					back.push(128 | (63 & (code >> 6)));
					back.push(128 | (63 & code));
				}
			}
			for (let i = 0; i < back.length; i++) {
				back[i] &= 0xff;
				backStr += String.fromCharCode(back[i]);
			}
			return backStr;
		},
		sleep(time) {
			const startTime = new Date().getTime() + parseInt(time, 10);
			while (new Date().getTime() < startTime) {}
		}
	}
};
</script>

<style lang="scss" scoped>
.page-gateway {
	padding-bottom: 130rpx;

	.no_tips {
		text-align: center;
		padding-top: 40%;
		font-size: 34rpx;
	}

	.state {
		padding: 0 20rpx;
	}

	.state_txt {
		padding: 10rpx 0;
		line-height: 80rpx;
		color: #1b1b19;
	}

	.state_txt > text {
		display: inline-block;
		width: 750rpx;
		color: #494949;
	}

	.state_txt > image {
		width: 110rpx;
		vertical-align: middle;
	}

	.state_bnt {
		padding-top: 30rpx;
		text-align: center;
	}

	.payment_txt {
		padding: 10rpx 0;
		line-height: 60rpx;
		color: #eb9a18;
	}

	.payment_txt > text {
		display: inline-block;
		color: #2f4d69;
		font-size: 36rpx;
	}

	.state_bnt button {
		width: 210rpx;
		height: 70rpx;
		border-radius: 70rpx;
		background: #f5a82c;
		color: #fff;
		line-height: 70rpx;
	}

	.state input {
		border: 1px solid #eee;
		border-radius: 8rpx;
		height: 80rpx;
		line-height: 80rpx;
		padding: 10rpx 20rpx;
		background: #fff;
	}

	.state .bnt {
		margin: 25rpx 20rpx 0;
		background: #e9930a;
		color: #fff;
		display: block;
		line-height: 100rpx;
		height: 100rpx;
		border-radius: 10rpx;
	}

	.popdiv {
		width: 100%;
		height: 100%;
		position: fixed;
		top: 0;
		left: 0;
		background: rgba(0, 0, 0, 0.7);
		text-align: center;
		display: none;
	}

	.popdiv.show {
		display: table;
	}

	.popcont {
		display: table-cell;
		vertical-align: middle;
	}

	.pop_text {
		width: 600rpx;
		background: #fff;
		border-radius: 15rpx;
		display: inline-block;
		text-align: left;
		overflow: hidden;
	}

	.pop_title {
		padding: 20rpx;
		font-size: 34rpx;
	}

	.pop_list {
		max-height: 60vh;
		overflow: auto;
		border-top: 1px solid #eee;
	}

	.pop_list > text,
	.pop_input label {
		display: block;
		padding: 20rpx;
		border-bottom: 1px solid #eee;
		position: relative;
		overflow: hidden;
	}

	.pop_list > text.crumb,
	.pop_input label.crumb {
		//noinspection CssUnknownTarget
		background: url('https://image.biandianxia.com/bdxcx/yes.png') no-repeat 96% center;
		background-size: 40rpx auto;
	}

	.pop_input {
		padding: 20rpx;
	}

	.pop_input input {
		border-bottom: 1px solid #3eb0f1;
		display: block;
		height: 60rpx;
		line-height: 60rpx;
	}

	.pop_input label checkbox {
		float: right;
	}

	.pop_input picker {
		padding: 15rpx 0;
	}

	.pop_bnt {
		padding: 30rpx 0 20rpx;
		text-align: center;
	}

	.pop_bnt button {
		margin: 0 20rpx;
		width: 260rpx;
		background: #fd393b;
		color: #fff;
		height: 80rpx;
		line-height: 80rpx;
		border-radius: 15rpx;
	}

	.pop_bnt button.show {
		display: inline-block;
	}
}
</style>